package cs340.stormtroopers.junitTests.phase4BlackBox;

import junit.framework.TestCase;
import cs340.stormtroopers.hypeerweb.ConcreteSendVisitor;
import cs340.stormtroopers.hypeerweb.Contents;
import cs340.stormtroopers.hypeerweb.HyPeerWeb;
import cs340.stormtroopers.hypeerweb.Node;
import cs340.stormtroopers.hypeerweb.Parameters;
import cs340.stormtroopers.hypeerweb.SendVisitor;

/**
 * Black box tests on the send operation.
 * Written from the spec with no knowledge of the code.
 * Yay!
 * @author Andy Morrow
 *
 */
public class SendTest extends TestCase
{
	/**
	 * Tests we will run
	 * - Equivalence Classes and Boundary Values
	 * 	- first boundary value: 1 node
	 * 		- 0 nodes - should fail
	 * 		- 1 node - should succeed
	 * 		- 2 nodes - should succeed
	 * 	- next equivalence class: small hypeerweb (3 nodes)
	 * 	- next equivalence class: small perfect hypercube (8 nodes)
	 * 	- next equivalence class: larger hypeerweb (50 nodes)
	 * 	- next equivalence class: larger perfect hypercube (64 nodes)
	 * 
	 * Equivalence classes for sending:
	 * 	- from node in first half of hypeerweb, receive node in second
	 * 	- vice versa
	 * 	- from and receive are same node
	 * 	- from and receive are same node in the middle of the hypeerweb
	 * 
	 * Also test boundary values - sending from first node to last node, second to next-to-last, etc.
	 */
	private void createHyPeerWeb(int numNodes)
	{
		HyPeerWeb hw = HyPeerWeb.getSingleton();
		hw.clear();
		for (int i = 0; i < numNodes; i++)
		{
			hw.addToHyPeerWeb(new Node(i), null);
		}
	}
	
	public void testSend()
	{
		// start out with base case - web of size 0
		createHyPeerWeb(0);
		// TODO make sure it doesn't work somehow
		
		// now begin testing our equivalence classes and boundary values for sizes
		int[] sizesToTest = {1, 2, 3, 8, 50, 64};
		for (int size : sizesToTest)
		{
			createHyPeerWeb(size);
			sendMessages();
		}
	}
	
	private void sendMessages()
	{
		HyPeerWeb hw = HyPeerWeb.getSingleton();
		Node sender = null, receiver = null;
		int size = hw.size();
		// first: from first node to last node
		sender = hw.getNode(0);
		receiver = hw.getNode(size-1);
		verifySend(sender, receiver);
		// then: from second to next-to-last
		// only makes sense if there are at least two nodes
		if (size >= 2)
		{
			sender = hw.getNode(1);
			receiver = hw.getNode(size-2);
			verifySend(sender, receiver);
		}
		// then: from a node 25% through to a node 75% through
		sender = hw.getNode((int)Math.round(0.25d * size));
		receiver = hw.getNode((int)Math.floor(0.75d * size));
		verifySend(sender, receiver);
		// then: from a node 75% through to a node 25% through
		Node temp = sender;
		sender = receiver;
		receiver = temp;
		verifySend(sender, receiver);
		// then: from the node 50% through to itself
		sender = hw.getNode((int)Math.floor(0.5d * size));
		receiver = sender;
		verifySend(sender, receiver);
	}
	
	private static final String MESSAGE = "got to final node!";
	private static final String MESSAGE_KEY = "message";
	private void verifySend(Node sender, Node receiver)
	{
		ConcreteSendVisitor sendVisitor = new ConcreteSendVisitor();
		int r = receiver.getWebIdValue();
		Parameters params = SendVisitor.createInitialParameters(r);
		params.set(MESSAGE_KEY, MESSAGE);
		sendVisitor.visit(sender, params);
		Contents contents = receiver.getContents();
		assertTrue(contents.containsKey(MESSAGE_KEY));
		assertTrue(contents.get(MESSAGE_KEY).equals(MESSAGE));
		contents.remove(MESSAGE_KEY);
	}
}
